Python 2 与 Python 3 的区别
信息安全公益宣传,信息安全知识启蒙。
加微信群回复公众号:微信群;QQ群:16004488
加微信群或QQ群可免费索取:学习教程
教程列表见微信公众号底部菜单
越来越多的库要放弃Python 2了,开始转向Python 3了。最近的项目开始用Python3写了,也体会了一下2和3的区别。主要的一些区别在以下几个方面:
print函数
整数相除
Unicode
异常处理
xrange
map函数
不支持has_key
print函数
Python 2中print是语句(statement),Python 3中print则变成了函数。在Python 3中调用print需要加上括号,不加括号会报SyntaxError
Python 2
print "hello world"
输出
hello world
Python 3
print("hello world")
输出
hello world
print "hello world"
输出
File "<stdin>", line 1
print "hello world"
^
SyntaxError: Missing parentheses in call to 'print'
整数相除
在Python 2中,3/2的结果是整数,在Python 3中,结果则是浮点数
Python 2
print '3 / 2 =', 3 / 2
print '3 / 2.0 =', 3 / 2.0
输出
3 / 2 = 1
3 / 2.0 = 1.5
Python 3
print('3 / 2 =', 3 / 2)
print('3 / 2.0 =', 3 / 2.0)
输出
3 / 2 = 1.5
3 / 2.0 = 1.5
Unicode
Python 2有两种字符串类型:str和unicode,Python 3中的字符串默认就是Unicode,Python 3中的str相当于Python 2中的unicode。
在Python 2中,如果代码中包含非英文字符,需要在代码文件的最开始声明编码,如下:
# -*- coding: utf-8 -*-
在Python 3中,默认的字符串就是Unicode,就省去了这个麻烦,下面的代码在Python 3可以正常地运行。
a = "你好"
print(a)
异常处理
Python 2中捕获异常一般用下面的语法
try:
1/0
except ZeroDivisionError, e:
print str(e)
或者
try:
1/0
except ZeroDivisionError as e:
print str(e)
Python 3中不再支持前一种语法,必须使用as关键字。
xrange
Python 2中有 range 和 xrange 两个方法。其区别在于,range返回一个list,在被调用的时候即返回整个序列;xrange返回一个iterator,在每次循环中生成序列的下一个数字。Python 3中不再支持 xrange 方法,Python 3中的 range 方法就相当于 Python 2中的 xrange 方法。
map函数
在Python 2中,map函数返回list,而在Python 3中,map函数返回iterator。
Python 2
map(lambda x: x+1, range(5))
输出
[1, 2, 3, 4, 5]
Python 3
map(lambda x: x+1, range(5))
输出
<map object at 0x7ff5b103d2b0>
list(map(lambda x: x+1, range(5)))
输出
[1, 2, 3, 4, 5]
filter函数在Python 2和Python 3中也是同样的区别。
不支持has_key
Python 3中的字典不再支持has_key方法
Python 2
person = {"age": 30, "name": "Xiao Wang"}
print "person has key \"age\": ", person.has_key("age")
print "person has key \"age\": ", "age" in person
输出
person has key "age": True
person has key "age": True
Python 3
person = {"age": 30, "name": "Xiao Wang"}
print("person has key \"age\": ", "age" in person)
输出
person has key "age": True
print("person has key \"age\": ", person.has_key("age"))
输出
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'has_key'
print函数
在py2中print是一个语法结构,而在py3中print是一个函数,
print(value, ..., sep=' ', end='\n',file=sys.stdout, flush=False)
file可以是文件,也就是可以把打印的东西直接输出到文件,这个就很方便,我经常用。比如:
a = range(10)
out_file = open(“print_test_file.txt”, ‘w’)
for x in a:
print(x,sep=’ ‘, end = “\n”, file=out_file)
编码问题
在py2中,编码问题是个大问题,可以单独拉出来讲一次。这里简单说一下,在py2中,把字符串分为Unicode和str两种类型。
>>> s1 = 'machine learning'
>>> type(s1)
<type 'str'>
>>> s2 = u'machine learning'
>>> type(s2)
<type 'unicode'>
>>> s3 = '中国'
>>> type(s3)
<type 'str'>
>>> s3
'\xd6\xd0\xb9\xfa'
>>> s4 = u'中国'
>>> type(s4)
<type 'unicode'>
py3中没有Unicode,他们都是字符串
>>> s1 = 'machine learning'
>>> type(s1)
<class 'str'>
>>>
>>> s2 = u'machine learning'
>>> type(s2)
<class 'str'>
>>> s3 = '中国'
>>> type(s3)
<class 'str'>
>>> s3
'中国'
当我们需要把py2中的unicode字符输出到文件或者传输到网络上,需要先把unicode字符转换为str类型,py2的encode方法就是编码unicode字符到指定字符类型,因为py2默认编码方式为unicode,所以当使用encode方式时,传入的参数就是目标编码格式,比如utf-8或者gbk等,当py2把一个字符存入到文件的时候,首先会判断字符的类型,如果是str,则直接存入文件,如果是Unicode类型,则先要转换为str类型,就需要encode方法,这时候默认的是ascii字符,然后ascii字符是不包括中文的,所以会引发UnicodeEncodeError。而decode是把str转换为unicode字符,刚说了py2的默认格式是unicode,所以decode的时候,需要传入的参数名字就是字符的现在的编码的编码方式,比如utf-8或者gbk,当传入的参数名字不是现在编码方式的时候,就会引发UnicodeDecodeError。
好了,这是py2中的坑,这些问题在py3中统统得到了解决。py3中没有Unicode和str的区别,Unicode字符也会当做utf-8来看待,我们知道utf-8是包括中文的,所以当把中文字符存入文件的时候,就不会发生编码问题。这也是为什么当代码中包括中文的时候,不需要在第一行显式的指定编码格式,# coding:utf-8.
除法问题
在py2中两个整数除法的得到的是0,要得到浮点数,则除数或者被除数有一个是浮点数,而在py3中,整数相除可以得到浮点数。但是如果要在py3中整数相除也得到0的话,就要使用//,而不是/。
# python2
print 1/2
>>> 0
print 1/2.
>>>0.5
# python3
print(1/2)
>>> 0.5
print(1//2)
>>> 0
nonlocal 语句
py3 新加入的,可以指定非全局变量。
输入函数
在py2中输入函数是raw_input和input两个函数, 而py3中删除了raw_inpus, 只使用input
I/O方法,xreadlines()
在py2中,一个文件对象有xreadlines()方法,返回一个迭代器,每次只读取一行数据,可以使用for循环输出结果。在py3中删除了这个方法。
cPickle
py2中的cPickle被移除,py3中被pickle代替。
urllib
py2中存在两个包,urllib和urllib2,是爬虫经常用的模块,py3中统一到了urllib中。并且py2中的urlparse模块被统一到了urllib.parse模块下。
包内的相对导入
这个挺重要的一个改变,需要掌握一下。在py2中,假设你写了三个.py的模块,比如:
--first.py
--second.py
--third.py
你想在3.py中导入1和2,可以直接
import first
import second
因为py2的解释器会首先在当前目录下搜索first和second,没有找到才会去python的路径中去找。而在py3中就不行,你需要这样做
from . import first
from . import second
因为py3会直接在python 的路径中去搜索,如果first.py和second.py在父目录当中,则需要这样
from .. import first
from .. import second
多加一个点,就这样,是不是很简单。
新式的8进制变量,修改了oct函数,oct是返回一个整形或者长整形的8进制数。
py2可以这样
>>> 0666
438
>>> oct(438)
‘0666’
在py3中
>>> 0666
SyntaxError: invalid token
>>> 0o666
438
>>> oct(438)
‘0o666’
新的super方法,可以不传参数
>>> class A(object):
def__init__(self, a):
print("A",a)
>>> class B(A):
def__init__(self, a):
super().__init__(a)
>>> B(8)
A 8
<__main__.B object at0x0000018FE6D0A198>
dict的.keys(),items(),values()方法返回一个迭代器,iterkeys(),has_key()废弃。
python3引入抽象基类
Abstract Base Classes, ABCs
迭代器
迭代器的next()方法改名为__next__,增加了内置函数next()
增加装饰器
@abstractmethod 和@anstractproperty两个新装饰器,编写抽象方法更加方便。
移除了imageop,audiodev, Bastion, bsddb,bsddb185, exceptions,linuxaudiodev, md5, MimeWrite, mimify, popen2, rexec, sets, sha, strinold,strop, sunaudiodev, timing, xmlib, new模块
这些是自带的模块,在py3中还移除了一些第三方模块。
os模块中的os.tmpnam()和os.tmpfile()移到tmpfile模块中
http
在py2中相关的模块由httplib,Cookie, cookielib, BaseHTTPServer, SimpleHTTPServer, CGIHttpServer,在py3中统一到了http模块中,变成http.client,http.cookies, http.cookiejar, http.server.
urllib
py2中存在两个包,urllib和urllib2,是爬虫经常用的模块,py3中统一到了urllib中。并且py2中的urlparse模块被统一到了urllib.parse模块下。
包内的相对导入
这个挺重要的一个改变,需要掌握一下。在py2中,假设你写了三个.py的模块,比如:
--first.py
--second.py
--third.py
你想在3.py中导入1和2,可以直接
import first
import second
因为py2的解释器会首先在当前目录下搜索first和second,没有找到才会去python的路径中去找。而在py3中就不行,你需要这样做
from . import first
from . import second
因为py3会直接在python 的路径中去搜索,如果first.py和second.py在父目录当中,则需要这样
from .. import first
from .. import second
多加一个点,就这样,是不是很简单。